﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace Components.CpfCnpjValidator
{
    public class CpfCnpjValidator: MaskedTextBox
    {
        ErrorProvider errorProvider = new ErrorProvider();
        bool _isCpf;

        [System.ComponentModel.DefaultValue(true)]
        public bool IsCpf
        {
            get { return _isCpf; }
            set 
            {
                Application.CurrentCulture = new System.Globalization.CultureInfo("pt-br");
                _isCpf = value;
                if (value)
                {
                    this.Mask = "000,000,000-00";
                }
                else
                    this.Mask = "00,000,000/0000-00";
            }
        }

        public bool HasError
        {
            get { return !string.IsNullOrEmpty(errorProvider.GetError(this)); }
        }

        public CpfCnpjValidator()
        {
            IsCpf = true;
            this.Validated += new EventHandler(CpfValidator_Validated);
        }

        void CpfValidator_Validated(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.Text))
            {
                errorProvider.SetError(this, "");
                return;
            }

            if (string.IsNullOrEmpty(this.Text.Replace("/", "").Replace(".", "").Replace("-", "").Trim()))
            {
                errorProvider.SetError(this, "");
                return;
            }

            if (IsCpf)
            {
                if (CpfCnpjValidator.ValidateCpf(this.Text))
                    errorProvider.SetError(this, "");
                else
                    errorProvider.SetError(this, "Cpf inválido!");
            }
            else
            {
                if (CpfCnpjValidator.ValidateCnpj(this.Text))
                    errorProvider.SetError(this, "");
                else
                    errorProvider.SetError(this, "Cnpj inválido!");
            }
        }

        #region Métodos
        private static int chInt(char ch)
        {
            int a = ch;
            int b = '0';
            return a - b;
        }

        private static char intCh(int i)
        {
            int b = '0';
            int a = i + b;
            char ch = Convert.ToChar(a);
            return ch;
        }

        private static string dvMod11Cnpj(string _str)
        {
            int soma = 0;
            int fator = 2;
            for (int i = _str.Length - 1; i >= 0; i--)
            {
                soma = soma + chInt(_str[i]) * fator;
                fator++;
                if (fator == 10)
                    fator = 2;
            }
            soma = 11 - (soma % 11);
            if (soma >= 10)
                return "0";
            else
                return soma.ToString();
        }

        private static string dvMod11Cpf(string _str)
        {
            int soma = 0;
            int fator = 2;
            for (int i = _str.Length - 1; i >= 0; i--)
            {
                soma = soma + chInt(_str[i]) * fator;
                fator++;
            }
            soma = 11 - (soma % 11);
            if (soma >= 10)
                return "0";
            else
                return soma.ToString();
        }

        private static string dvCnpj(string _str)
        {
            string dv1 = dvMod11Cnpj(_str);
            return dv1 + dvMod11Cnpj(_str + dv1);
        }

        private static string dvCpf(string _str)
        {
            string dv1 = dvMod11Cpf(_str);
            return dv1 + dvMod11Cpf(_str + dv1);
        }

        /// <summary>
        /// Recebe um Cnpj no formato de string e retorna se ele é verdadeiro ou não.
        /// </summary>
        /// <param name="CNPJ">Apenas dígitos</param>
        /// <returns></returns>
        public static bool ValidateCnpj(string Cnpj)
        {
            Cnpj = Cnpj.Replace(".", "");
            Cnpj = Cnpj.Replace("-", "");
            Cnpj = Cnpj.Replace("/", "");

            if (Cnpj.Length == 14)
                return Cnpj.Substring(12, 2) == dvCnpj(Cnpj.Substring(0, 12));
            else
                return false;
        }

        /// <summary>
        /// Recebe um CPF no formato de string e retorna se ele é verdadeiro ou não.
        /// </summary>
        /// <param name="CPF">Apenas dígitos</param>
        /// <returns></returns>
        public static bool ValidateCpf(string _str)
        {
            _str = _str.Replace(".", "");
            _str = _str.Replace("-", "");
            _str = _str.Replace("/", "");

            if (_str.Length == 11)
                return _str.Substring(9, 2) == dvCpf(_str.Substring(0, 9));
            else
                return false;
        }

        #endregion   
    }
}
